﻿using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using W = DocumentFormat.OpenXml.Wordprocessing;
namespace DataService.Office.Word
{

    public class XmlPackageTitle
    {
        private static string defaultFontName = "微软雅黑";
        private static string defaultFontSize = "21";
        //标题字体大小
        private static string titleFontSize = "24";
        //  private List<int> newLevelList = new List<int>();

        /// <summary>
        /// 返回word中的标题
        /// </summary>
        /// <param name="body"></param>
        /// <param name="level">1:一级标题 2：二级标题 3:三级标题 4：四级标题...9:九级标题</param>
        /// <returns></returns>
        public static List<string> GetWordTitle(MainDocumentPart mainPart, Body body, int level)
        {
            if (level > 9 || level < 1)
            {
                return new List<string>();
            }
            System.Xml.Linq.XDocument xmlDocument = XmlPackagePart.WDExtractStyles(mainPart, false);
            List<string> list = new List<string>();
            foreach (var openXmlElement in body.ChildElements)
            {
                if (openXmlElement is Paragraph)
                {
                    //word中标题有两种
                    //一种是【heading 1】【heading 2】或者【标题 1】【标题 2】
                    //第二种是样式标题
                    //1.获取【heading 1】...【heading 9】这类的标题
                    #region 获取【heading 1】...【heading 9】这类的标题
                    string tempTitle = GetGetWordTitleByHead(xmlDocument, openXmlElement, level);
                    if (!string.IsNullOrEmpty(tempTitle))
                    {
                        list.Add(tempTitle);
                    }
                    #endregion
                    #region 获取样式标题

                    #endregion
                    //读取域代码
                    // var styles = paragraph.Descendants<ParagraphStyleId>();
                    //var stringValue = new StringValue(level.ToString());
                    //var tempParagraphStyleId = styles.FirstOrDefault(x => x.Val == stringValue);
                    //if (tempParagraphStyleId != null)
                    //{
                    //    var bookmarkStartList = paragraph.Descendants<BookmarkStart>();
                    //    if (!string.IsNullOrEmpty(paragraph.InnerText) && bookmarkStartList.Count() > 0)
                    //    {
                    //        //获取文本方式一
                    //        //paragraph.InnerText会获取到域代码,paragraph.InnerText获取值后还要处理域代码,所以暂时不用这种方式获取文本
                    //        // list.Add(paragraph.InnerText);
                    //        //获取文本方式二
                    //        var textList = paragraph.Descendants<Text>().ToList();
                    //        var textValueList = textList.Select(x => x.InnerText);
                    //        list.Add(string.Join("", textValueList));
                    //    }
                    //}
                }
            }
            return list;
        }
        /// <summary>
        ///获取word标题
        ///标题样式为【heading 1】【heading 2】...【heading 9】
        ///或者
        ///标题样式为【标题 1】【标题 2】...【标题 9】
        /// </summary>
        /// <param name="openXmlElement"></param>
        /// <param name="level">1:一级标题 2：二级标题 3:三级标题 4：四级标题</param>
        /// <param name="xmlDocument">word的样式XML结构【可以放到静态集合里面,可以提高查找速度,暂时不处理】</param>
        /// <returns></returns>
        public static string GetGetWordTitleByHead(System.Xml.Linq.XDocument xmlDocument, OpenXmlElement openXmlElement, int level)
        {
            if (level < 1 || level > 9)
                throw new Exception("标题等级参数错误");
            if (openXmlElement is Paragraph)
            {
                var styleIdList = XmlStyle.GetStyleId(openXmlElement);
                if (styleIdList.Count == 0)
                {
                    return string.Empty;
                }
                foreach (var tempStyleId in styleIdList)
                {
                    IEnumerable<XElement> tempXElementList = XmlPackagePart.GetParagraphXMLStyleByStyleId(xmlDocument, tempStyleId);
                    foreach (var item in tempXElementList)
                    {
                        string tempStyleName = XmlPackagePart.GetValueByXElementNodeName(item, "name", "val");
                        tempStyleName = tempStyleName.ToLower();
                        if (tempStyleName == "heading " + level || tempStyleName == "标题 " + level)
                        {
                            //获取文本方式一
                            //paragraph.InnerText会获取到域代码,paragraph.InnerText获取值后还要处理域代码,所以暂时不用这种方式获取文本
                            // list.Add(paragraph.InnerText);
                            //获取文本方式二
                            var textList = openXmlElement.Descendants<Text>().ToList();
                            var textValueList = textList.Select(x => x.InnerText);
                            return string.Join("", textValueList);
                        }
                    }
                }
            }
            return string.Empty;
        }




        public static void ParagraphAppendTitle(Paragraph paragraph, string text, int level)
        {
            // newLevelList.Add(level);
            string bookmarkId = Guid.NewGuid().ToString().Replace("-", "");
            //titleNum++;
            //W.Paragraph paragraph = new W.Paragraph();

            W.ParagraphProperties paragraphPraperties = new W.ParagraphProperties();
            W.ParagraphStyleId paragraphStyleId = new W.ParagraphStyleId() { Val = level.ToString() };
            //修饰段落
            W.ParagraphMarkRunProperties paragraphMarkRunProperties = new W.ParagraphMarkRunProperties();

            //字体
            W.RunFonts runFonts1 = new W.RunFonts() { Ascii = defaultFontName, HighAnsi = defaultFontName, EastAsia = defaultFontName };
            //字的大小
            W.FontSize fontSize1 = new W.FontSize() { Val = defaultFontSize };

            paragraphMarkRunProperties.Append(runFonts1);
            paragraphMarkRunProperties.Append(fontSize1);
            paragraphPraperties.Append(paragraphStyleId);
            paragraphPraperties.Append(paragraphMarkRunProperties);

            //原来方式,若出错则需要回滚到这个示例
            //  W.BookmarkStart bookmarkStart1 = new W.BookmarkStart() { Name = "_Toc" + titleNum, Id = titleNum.ToString() };
            W.BookmarkStart bookmarkStart1 = new W.BookmarkStart() { Name = "_Toc" + bookmarkId, Id = bookmarkId.ToString() };

            W.Run run = new W.Run();

            W.RunProperties runProperties = new W.RunProperties();
            W.RunFonts runFonts = new W.RunFonts() { Hint = W.FontTypeHintValues.EastAsia, Ascii = defaultFontName, HighAnsi = defaultFontName, EastAsia = defaultFontName };
            W.FontSize fontSize = new W.FontSize() { Val = titleFontSize };
            runProperties.Append(runFonts);
            runProperties.Append(fontSize);
            W.LastRenderedPageBreak lrp = new W.LastRenderedPageBreak();
            W.Text text1 = new W.Text();
            text1.Text = text;
            run.Append(runProperties);
            run.Append(lrp);
            run.Append(text1);

            W.BookmarkEnd bookmarkEnd1 = new W.BookmarkEnd { Id = bookmarkId };

            paragraph.Append(paragraphPraperties);
            paragraph.Append(bookmarkStart1);
            paragraph.Append(run);
            paragraph.Append(bookmarkEnd1);

        }
        private static Style CreateTitleStyle(int titleIndex)
        {
            string titleID = titleIndex.ToString();
            string rsid = string.Empty;
            string before = string.Empty;
            string after = string.Empty;
            string line = string.Empty;
            string val = string.Empty;
            int outline = titleIndex - 1;
            if (titleIndex == 3)
            {
                rsid = "00BA1E93";
                before = "130";//"260"
                after = "0";
                line = "286";//"416"
                val = "32";

            }
            else if (titleIndex == 4)
            {
                rsid = "00BA1E94";
                before = "88";
                after = "0";
                line = "288";//"376"
                val = "28";
            }
            else if (titleIndex == 5)
            {
                rsid = "00BA1E95";
                before = "88";
                after = "0";
                line = "290";
                val = "24";
            }
            else if (titleIndex == 6)
            {
                rsid = "00BA1E96";
                before = "88";
                after = "0";
                line = "292";
                val = "20";
            }
            else if (titleIndex == 7)
            {
                rsid = "00BA1E97";
                before = "88";
                after = "0";
                line = "294";
                val = "16";
            }
            else if (titleIndex == 8)
            {
                rsid = "00BA1E98";
                before = "88";
                after = "0";
                line = "296";
                val = "14";
            }
            else if (titleIndex == 9)
            {
                rsid = "00BA1E99";
                before = "88";
                after = "0";
                line = "298";
                val = "12";
            }
            Style style2 = new Style() { Type = StyleValues.Paragraph, StyleId = titleID };
            StyleName styleName2 = new StyleName() { Val = "heading " + titleID };
            BasedOn basedOn1 = new BasedOn() { Val = "a" };
            NextParagraphStyle nextParagraphStyle1 = new NextParagraphStyle() { Val = "a" };
            LinkedStyle linkedStyle1 = new LinkedStyle() { Val = titleID + "Char" };
            UIPriority uIPriority1 = new UIPriority() { Val = 9 };
            PrimaryStyle primaryStyle2 = new PrimaryStyle();
            Rsid rsid2 = new Rsid() { Val = rsid };
            style2.Append(styleName2);
            style2.Append(basedOn1);
            style2.Append(nextParagraphStyle1);
            style2.Append(linkedStyle1);
            style2.Append(uIPriority1);
            style2.Append(primaryStyle2);
            style2.Append(rsid2);

            StyleParagraphProperties styleParagraphProperties2 = new StyleParagraphProperties();
            KeepNext keepNext1 = new KeepNext();
            KeepLines keepLines1 = new KeepLines();
            SpacingBetweenLines spacingBetweenLines1 = new SpacingBetweenLines() { Before = before, After = after, Line = line, LineRule = LineSpacingRuleValues.Auto };
            OutlineLevel outlineLevel1 = new OutlineLevel() { Val = outline };
            styleParagraphProperties2.Append(keepNext1);
            styleParagraphProperties2.Append(keepLines1);
            styleParagraphProperties2.Append(spacingBetweenLines1);
            styleParagraphProperties2.Append(outlineLevel1);
            style2.Append(styleParagraphProperties2);

            StyleRunProperties styleRunProperties1 = new StyleRunProperties();
            Bold bold1 = new Bold();
            BoldComplexScript boldComplexScript1 = new BoldComplexScript();
            // Kern kern2 = new Kern() { Val = (UInt32)44U };
            FontSize fontSize2 = new FontSize() { Val = val };
            FontSizeComplexScript fontSizeComplexScript2 = new FontSizeComplexScript() { Val = val };
            styleRunProperties1.Append(bold1);
            styleRunProperties1.Append(boldComplexScript1);
            //styleRunProperties1.Append(kern2);
            styleRunProperties1.Append(fontSize2);
            styleRunProperties1.Append(fontSizeComplexScript2);
            style2.Append(styleRunProperties1);
            return style2;
        }


        public static void CreateDefinitionsPart(MainDocumentPart mainPart, List<int> newLevelList)
        {
            //var paragraphs = mainPart.Document.Descendants<Paragraph>();
            if (newLevelList==null||newLevelList.Count == 0)
                return;
            if (newLevelList.Any(x => x > 9 || x < 1))
            {
                return;
            }
            newLevelList = newLevelList.Distinct().ToList();
            StyleDefinitionsPart styleDefinitionsPart = mainPart.StyleDefinitionsPart;
            if (styleDefinitionsPart == null)
            {
                styleDefinitionsPart = mainPart.AddNewPart<StyleDefinitionsPart>("rId1");
            }
            bool isAdd = false;
            W.Styles styles1 = styleDefinitionsPart.Styles;
            if (styles1 == null)
            {
                styles1 = new W.Styles();
                isAdd = true;
            }
            string r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
            string w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
            var nameSpaces = styles1.NamespaceDeclarations;
            if (nameSpaces.Count() == 0)
            {
                styles1.AddNamespaceDeclaration("r", r);
                styles1.AddNamespaceDeclaration("w", w);
            }
            else
            {
                if (!nameSpaces.Any(x => x.Value == r))
                {
                    styles1.AddNamespaceDeclaration("r", r);
                }
                if (!nameSpaces.Any(x => x.Value == w))
                {
                    styles1.AddNamespaceDeclaration("w", w);
                }
            }
            foreach (var itemLevel in newLevelList)
            {
                if (itemLevel == 1)
                {
                    Style headingstyle1 = CreateFirstTitle();
                    styles1.Append(headingstyle1);
                }
                else if (itemLevel == 2)
                {
                    Style headingstyle2 = CreateSecondTitle();
                    styles1.Append(headingstyle2);
                }
                else
                {
                    Style headingstyle = CreateTitleStyle(itemLevel);
                    styles1.Append(headingstyle);
                }
            }
            if (isAdd)
            {
                styleDefinitionsPart.Styles = styles1;
            }



            //以下方式，只能对空白文档起作用  
            //Style headingstyle4 = CreateTitleStyle(4);
            //Style headingstyle5 = CreateTitleStyle(5);
            //Style headingstyle6 = CreateTitleStyle(6);
            //Style headingstyle7 = CreateTitleStyle(7);
            //Style headingstyle8 = CreateTitleStyle(8);
            //Style headingstyle9 = CreateTitleStyle(9);
            //styles1.Append(headingstyle3);
            //styles1.Append(headingstyle4);
            //styles1.Append(headingstyle5);
            //styles1.Append(headingstyle6);
            //styles1.Append(headingstyle7);
            //styles1.Append(headingstyle8);
            //styles1.Append(headingstyle9);
            //styleDefinitionsPart.Styles = styles1;

        }

        private static Style CreateFirstTitle()
        {
            #region 一级标题
            W.Style style2 = new W.Style() { Type = W.StyleValues.Paragraph, StyleId = "1" };
            W.StyleName styleName2 = new W.StyleName() { Val = "heading 1" };
            W.BasedOn basedOn1 = new W.BasedOn() { Val = "a" };
            W.NextParagraphStyle nextParagraphStyle1 = new W.NextParagraphStyle() { Val = "a" };
            W.LinkedStyle linkedStyle1 = new W.LinkedStyle() { Val = "1Char" };
            W.UIPriority uIPriority1 = new W.UIPriority() { Val = 9 };
            W.PrimaryStyle primaryStyle2 = new W.PrimaryStyle();
            W.Rsid rsid1 = new W.Rsid() { Val = "00861388" };

            W.StyleParagraphProperties styleParagraphProperties2 = new W.StyleParagraphProperties();
            W.KeepNext keepNext1 = new W.KeepNext();
            W.KeepLines keepLines1 = new W.KeepLines();
            W.SpacingBetweenLines spacingBetweenLines1 = new W.SpacingBetweenLines() { Before = "340", After = "330", Line = "578", LineRule = W.LineSpacingRuleValues.Auto };
            W.OutlineLevel outlineLevel1 = new W.OutlineLevel() { Val = 0 };

            styleParagraphProperties2.Append(keepNext1);
            styleParagraphProperties2.Append(keepLines1);
            styleParagraphProperties2.Append(spacingBetweenLines1);
            styleParagraphProperties2.Append(outlineLevel1);

            W.StyleRunProperties styleRunProperties1 = new W.StyleRunProperties();
            W.Bold bold1 = new W.Bold();
            W.BoldComplexScript boldComplexScript1 = new W.BoldComplexScript();
            W.Kern kern2 = new W.Kern() { Val = (UInt32Value)44U };
            W.FontSize fontSize2 = new W.FontSize() { Val = "44" };
            W.FontSizeComplexScript fontSizeComplexScript2 = new W.FontSizeComplexScript() { Val = "44" };

            styleRunProperties1.Append(bold1);
            styleRunProperties1.Append(boldComplexScript1);
            styleRunProperties1.Append(kern2);
            styleRunProperties1.Append(fontSize2);
            styleRunProperties1.Append(fontSizeComplexScript2);

            style2.Append(styleName2);
            style2.Append(basedOn1);
            style2.Append(nextParagraphStyle1);
            style2.Append(linkedStyle1);
            style2.Append(uIPriority1);
            style2.Append(primaryStyle2);
            style2.Append(rsid1);
            style2.Append(styleParagraphProperties2);
            style2.Append(styleRunProperties1);
            #endregion

            return style2;
        }

        private static Style CreateSecondTitle()
        {
            #region 二级标题
            W.Style style3 = new W.Style() { Type = W.StyleValues.Paragraph, StyleId = "2" };
            W.StyleName styleName3 = new W.StyleName() { Val = "heading 2" };
            W.BasedOn basedOn2 = new W.BasedOn() { Val = "a" };
            W.NextParagraphStyle nextParagraphStyle2 = new W.NextParagraphStyle() { Val = "a" };
            W.LinkedStyle linkedStyle2 = new W.LinkedStyle() { Val = "2Char" };
            W.UIPriority uIPriority2 = new W.UIPriority() { Val = 9 };
            W.UnhideWhenUsed unhideWhenUsed1 = new W.UnhideWhenUsed();
            W.PrimaryStyle primaryStyle3 = new W.PrimaryStyle();
            W.Rsid rsid2 = new W.Rsid() { Val = "00853401" };

            W.StyleParagraphProperties styleParagraphProperties3 = new W.StyleParagraphProperties();
            W.KeepNext keepNext2 = new W.KeepNext();
            W.KeepLines keepLines2 = new W.KeepLines();
            W.SpacingBetweenLines spacingBetweenLines2 = new W.SpacingBetweenLines() { Before = "260", After = "260", Line = "416", LineRule = W.LineSpacingRuleValues.Auto };
            W.OutlineLevel outlineLevel2 = new W.OutlineLevel() { Val = 1 };

            styleParagraphProperties3.Append(keepNext2);
            styleParagraphProperties3.Append(keepLines2);
            styleParagraphProperties3.Append(spacingBetweenLines2);
            styleParagraphProperties3.Append(outlineLevel2);

            W.StyleRunProperties styleRunProperties2 = new W.StyleRunProperties();
            W.RunFonts runFonts2 = new W.RunFonts() { AsciiTheme = W.ThemeFontValues.MajorHighAnsi, HighAnsiTheme = W.ThemeFontValues.MajorHighAnsi, EastAsiaTheme = W.ThemeFontValues.MajorEastAsia, ComplexScriptTheme = W.ThemeFontValues.MajorBidi };
            W.Bold bold2 = new W.Bold();
            W.BoldComplexScript boldComplexScript2 = new W.BoldComplexScript();
            W.FontSize fontSize3 = new W.FontSize() { Val = "32" };
            W.FontSizeComplexScript fontSizeComplexScript3 = new W.FontSizeComplexScript() { Val = "32" };

            styleRunProperties2.Append(runFonts2);
            styleRunProperties2.Append(bold2);
            styleRunProperties2.Append(boldComplexScript2);
            styleRunProperties2.Append(fontSize3);
            styleRunProperties2.Append(fontSizeComplexScript3);

            style3.Append(styleName3);
            style3.Append(basedOn2);
            style3.Append(nextParagraphStyle2);
            style3.Append(linkedStyle2);
            style3.Append(uIPriority2);
            style3.Append(unhideWhenUsed1);
            style3.Append(primaryStyle3);
            style3.Append(rsid2);
            style3.Append(styleParagraphProperties3);
            style3.Append(styleRunProperties2);
            #endregion

            return style3;
        }
    }
}
